/**
 * \file packet_ip.c
 * \brief Packet IP
 * \author Pierre Neumann / Julien Meutelet
 * \version 0.1
 * \date 20 decembre 2013
 *
 * Sert à Initialiser l'entête IP et à l'afficher
 *
 */
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h> 
#include <netinet/ip_icmp.h> 
#include <arpa/inet.h>

#include "packet_utils.h"
#include "packet_ip.h"
#include "packet_icmp.h"
#include "packet_udp.h"
#include "packet_tcp.h"

const size_t IP_HEADER_SIZE = sizeof(struct ip); /*!< Taille de l'entête IP */

/**
 * \fn init_ip_header(char** packet, struct in_addr* destination, struct in_addr* source, size_t protocol_header_size,int protocol_number, int ttl)
 * \brief Initialise l'entête IP
 *
 * \param packet Chaine de caractère représentant le paquet.
 * \param destination Pointeur vers la structure in_addr de la destination.
 * \param source Pointeur vers la structure in_addr de la source.
 * \param protocol_header_size Taille de l'entête du protocole utilisé.
 * \param protocol_number Entier, numéro du protocole utilisé (ICMP, UDP, TCP).
 * \param ttl Entier utilisé pour initialiser le champ ttl de l'entête IP.
 * \return Rien.
 */
void init_ip_header(char** packet, struct in_addr* destination, struct in_addr* source, size_t protocol_header_size,int protocol_number, int ttl){
	
	struct ip *hip = (struct ip *) *packet;

	// Version :
	// Ici IPv4
	hip->ip_v = 4;

	// Taille normale sans options en nombre de mots
	// 5 mots de 32 bits => 4 octets
	hip->ip_hl = 5;

	// TOS  
	hip->ip_tos = 0; 

	// Nombre total d'octets du datagram 
	// ici taille de l'entête IP + taille de l'entête selon le protocol (ICMP, TCP, UDP)
	hip->ip_len = IP_HEADER_SIZE + protocol_header_size; 

	// Fragment offset
	hip->ip_off = htons(0x4000); //DF : don't fragment

	// Id du paquet  
	hip->ip_id = htons(getuid());

	// TTL
	hip->ip_ttl = ttl;

	// Numéro du protocole
	// 1 pour ICMP -- 6 pour TCP -- 17 pour UDP
	hip->ip_p = protocol_number; 

	// Adresse ip source 
	hip->ip_src = *source;

	// Adresse ip du destinataire
	hip->ip_dst = *destination;

	// Checksum du paquet
	hip->ip_sum = checksum((unsigned short *)hip, IP_HEADER_SIZE);
}

/**
 * \fn is_protocol(char** packet,int protocol_number)
 * \brief Teste le protocole du paquet
 *
 * \param packet Chaine de caractère représentant le paquet.
 * \param protocol_number Entier, numéro du protocole utilisé (ICMP, UDP, TCP).
 * \return Renvoie 1 si le paquet est du protocole passé en paramètre, 0 sinon.
 */
int is_protocol(char** packet,int protocol_number){
	struct ip *hip = (struct ip *) *packet;
	return hip->ip_p == protocol_number;
}

/**
 * \fn print_ip_header(char** packet)
 * \brief Affiche un paquet.
 *
 * \param packet Chaine de caractère représentant le paquet.
 * \return Rien.
 */
void print_ip_header(char** packet){
	struct ip *hip = (struct ip *) *packet;
	printf("------Entête IP------\n");
	printf("Version : %d\n",hip->ip_v);
	printf("IHL : %d\n",hip->ip_hl);
	printf("TOS : %d\n",hip->ip_tos);
	printf("Longueur Totale : %d\n",hip->ip_len);
	printf("Id : %d\n",hip->ip_id);
	printf("Fragment Offset : %d\n",hip->ip_off);
	printf("TTL : %d\n",hip->ip_ttl);
	printf("Protocol : %d\n",hip->ip_p);
	printf("Checksum : %d\n",hip->ip_sum);
	printf("IP source : %s\n",inet_ntoa(hip->ip_src));
	printf("IP destination : %s\n",inet_ntoa(hip->ip_dst)); 
	// On affiche l'entête correspondant au protocole
	switch(hip->ip_p){
		case 1  : print_icmp_header(packet);break; 
		case 6  : print_tcp_header(packet);break; 
		case 17 : print_udp_header(packet);break; 
		default : printf("Protocole inconnu");break; 
	}
}

